/*******************************************************************************
 * This file is part of blueprint4j www.blueprint4j.org.
 * 
 *     blueprint4j is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     blueprint4j is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 * 
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with blueprint4j. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package blueprint4j.gui;

import blueprint4j.utils.*;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;

public class SettingsControl extends JPanel implements SaveableComponent{
	private SettingsStore store = null;
	private JTree tree = null;

	public SettingsControl() {
		this(Settings.getSettingsStore());
	}

	public SettingsControl(SettingsStore p_store) {
		super(new BorderLayout());
		store = p_store;
		build();
	}

	private void build() {
		DefaultMutableTreeNode root = new DefaultMutableTreeNode();
		Vector v = new Vector();
		Enumeration e = store.getSettingNames();
		while (e.hasMoreElements()) {
			v.add((String)e.nextElement());
		}
		Object[] o = v.toArray();
		Arrays.sort(o);
		for (int t = 0;t < o.length;t++) {
			String entry = (String)o[t];
			StringTokenizer st = new StringTokenizer(entry, ".");
			DefaultMutableTreeNode node = root;
			while (st.hasMoreElements()) {
				String name = (String)st.nextElement();
				// Check if we can find this node
				boolean found = false;
				Enumeration children = node.children();
				while (children.hasMoreElements() && !found) {
					DefaultMutableTreeNode child = (DefaultMutableTreeNode)children.nextElement();
					if (name.equals(((SettingsString)(child.getUserObject())).name)) {
						node = child;
						found = true;
					}
				}
				// Add node
				SettingsString settings;
				if (!found) {
					settings = new SettingsString(name, store);
					DefaultMutableTreeNode new_node = new DefaultMutableTreeNode(settings);
					node.add(new_node);
					node = new_node;
				}
				settings = (SettingsString)node.getUserObject();
				if (!st.hasMoreElements()) {
					settings.setSettingsString(entry);
				}
			}
		}

		// Build tree
		tree = new JTree(root);
		tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		tree.setCellEditor(new SettingsCellEditor());
		tree.setEditable(true);
		add(new JScrollPane(tree));
	}

	// Stand alone editing for file based
	public static void main(String[] args) {
		try {
			if (args.length == 0) {
				Log.info.out("Please supply the name of the settings file.");
				return ;
			}
			JFrame frame = new JFrame("Settings Editor '"+args[0]+"'");
			JOptionPane.setRootFrame(frame);
			frame.getContentPane().setLayout(new BorderLayout());
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			frame.getContentPane().add(
				new SettingsControl(
					new SettingsStorePropertiesFile(args[0])
				)
			);
			frame.setSize(500,400);
			frame.setVisible(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	class SettingsCellEditor implements TreeCellEditor {
		private DefaultMutableTreeNode node=null;
		private JTextArea text;

		public Component getTreeCellEditorComponent(
			JTree tree,
			Object value,
			boolean isSelected,
			boolean expanded,
			boolean leaf,
			int row
		) {
			SettingsString ss=(SettingsString)((DefaultMutableTreeNode)value).getUserObject();
			JPanel panel = new JPanel(new BorderLayout());
			panel.add(new JLabel(ss.getName()), BorderLayout.WEST);
			int deapth=8;
			String svalue=ss.getSettingsStore().getString(ss.getSettingsString(), "-");
			if (svalue.length()<30) deapth=1;
			text=new JTextArea(svalue,deapth,30);
			text.setWrapStyleWord(true);
			text.setLineWrap(true);
			panel.add(new JScrollPane(text));
			panel.setBorder(BorderFactory.createEtchedBorder());
			return panel;
		}

		//Adds a listener to the list that's notified when the editor stops, or cancels editing.
		public void addCellEditorListener(CellEditorListener l) {
		}

		//Tells the editor to cancel editing and not accept any partially edited value.
		public void cancelCellEditing() {
			SettingsString ss=(SettingsString)node.getUserObject();
			ss.setValue(text.getText());
		}

		//Returns the value contained in the editor.
		public Object getCellEditorValue() {
			return null;
		}

		//Asks the editor if it can start editing using anEvent.
		public boolean isCellEditable(EventObject anEvent) {
			MouseEvent me=(MouseEvent)anEvent;
			JTree tree=(JTree)anEvent.getSource();
			TreePath path=tree.getClosestPathForLocation(me.getX(),me.getY());
			node=(DefaultMutableTreeNode)path.getLastPathComponent();
			SettingsString ss=(SettingsString)node.getUserObject();
			return ss.isEditable() && me.getClickCount()>1;
		}

		//Removes a listener from the list that's notified
		public void removeCellEditorListener(CellEditorListener l) {}

		//Returns true if the editing cell should be selected, false otherwise.
		public boolean shouldSelectCell(EventObject anEvent) {
			return isCellEditable(anEvent);
		}

		//Tells the editor to stop editing and accept any partially edited value as the value of the editor.
		public boolean stopCellEditing() {
			SettingsString ss=(SettingsString)node.getUserObject();
			ss.setValue(text.getText());
			return true;
		}

	}

	class SettingsString {
		String name, settings_name = null;
		SettingsStore store;

		SettingsString(String p_name, SettingsStore p_store) {
			store = p_store;
			name = p_name;
		}

		boolean isEditable(){
			return settings_name!=null;
		}

		void setSettingsString(String p_settings_name) {
			settings_name = p_settings_name;
		}

		String getSettingsString() {
			return settings_name;
		}

		String getName() {
			return name;
		}

		SettingsStore getSettingsStore() {
			return store;
		}

		public void setValue(String new_value){
			store.setString(settings_name,new_value);
			store.save();
		}

		public String toString() {
			if (settings_name != null) {
				String value = "(" + store.getString(settings_name, "-") + ")";
				if (value.length() > 20) value = value.substring(0, 16) + "...)";
				return name + " " + value;
			}
			return name;
		}
	}
	
	public boolean save() {return true;}
	public JComponent getComponent() {
		return this;
	}
}

